#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include "StaticMethodCall.h"

jstring MyNewString(JNIEnv *env, jchar *chars, jint len);

JNIEXPORT void JNICALL
Java_StaticMethodCall_nativeMethod(JNIEnv *env, jobject obj)
{
	jclass cls = (*env)->GetObjectClass(env, obj);
	jmethodID mid = (*env)->GetStaticMethodID(env, cls, "callback", "()V");
	if (mid == NULL) {
		return; /* method not found */
	}
	printf("In C\n");
	(*env)->CallStaticVoidMethod(env, cls, mid);

	/*********************************/
}

//调用构造函数
jstring MyNewString(JNIEnv *env, jchar *chars, jint len)
{
#if 0
	jclass stringClass;
	jmethodID cid;
	jcharArray elemArr;
	jstring result;
	stringClass = (*env)->FindClass(env, "java/lang/String");
	if (stringClass == NULL) {
		return NULL; /* exception thrown */
	}
	/* Get the method ID for the String(char[]) constructor */
	cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V");
	if (cid == NULL) {
	return NULL; /* exception thrown */
	}
	/* Create a char[] that holds the string characters */
	elemArr = (*env)->NewCharArray(env, len);
	if (elemArr == NULL) {
		return NULL; /* exception thrown */
	}
	(*env)->SetCharArrayRegion(env, elemArr, 0, len, chars);
	/* Construct a java.lang.String object */
#if 0	
	result = (*env)->NewObject(env, stringClass, cid, elemArr);//此方法调用构造函数更常用，不易出错
#else
	//创建一个未初始化对象，最多只能调用一次构造函数
	result = (*env)->AllocObject(env, stringClass);
	if (result) {
		(*env)->CallNonvirtualVoidMethod(env, result, stringClass, cid, elemArr);
		/* we need to check for possible exceptions */
		if ((*env)->ExceptionCheck(env)) {
			(*env)->DeleteLocalRef(env, result);
			result = NULL;
		}
	}	
#endif	
	/* Free local references */
	(*env)->DeleteLocalRef(env, elemArr);
	(*env)->DeleteLocalRef(env, stringClass);
	return result;
#else //global reference 
	static jclass stringClass = NULL;
	jmethodID cid;
	jcharArray elemArr;
	jstring result;
	if (stringClass == NULL) {
		jclass localRefCls = 
			(*env)->FindClass(env, "java/lang/String");
		if (localRefCls == NULL) {
			return NULL;
		}
		/* Create a global reference */
		stringClass = (*env)->NewGlobalRef(env, localRefCls);
		/* The local reference is no longer useful */
		(*env)->DeleteLocalRef(env, localRefCls);
		/* Is the global reference created successfully? */
		if (stringClass == NULL) {
			return NULL; /* exception thrown */
		}		
	}

	/* Get the method ID for the String(char[]) constructor */
	cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V");
	if (cid == NULL) {
	return NULL; /* exception thrown */
	}
	/* Create a char[] that holds the string characters */
	elemArr = (*env)->NewCharArray(env, len);
	if (elemArr == NULL) {
		return NULL; /* exception thrown */
	}
	(*env)->SetCharArrayRegion(env, elemArr, 0, len, chars);
	/* Construct a java.lang.String object */
#if 0	
	result = (*env)->NewObject(env, stringClass, cid, elemArr);//此方法调用构造函数更常用，不易出错
#else
	//创建一个未初始化对象，最多只能调用一次构造函数
	result = (*env)->AllocObject(env, stringClass);
	if (result) {
		(*env)->CallNonvirtualVoidMethod(env, result, stringClass, cid, elemArr);
		/* we need to check for possible exceptions */
		if ((*env)->ExceptionCheck(env)) {
			(*env)->DeleteLocalRef(env, result);
			result = NULL;
		}
	}	
#endif	
	/* Free local references */
	(*env)->DeleteLocalRef(env, elemArr);
	(*env)->DeleteLocalRef(env, stringClass);
	return result;	
#endif	
}
jclass Class_java_lang_String;
jmethodID MID_String_init;
//Creating jstrings from Native Strings
jstring JNI_NewStringNative(JNIEnv *env, const char *str)
{
	jstring result;
	jbyteArray bytes = 0;
	int len;
	if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
		return NULL; /* out of memory error */
	}
	len = strlen(str);
	bytes = (*env)->NewByteArray(env, len);
	if (bytes != NULL) {
		(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *)str);
		//Class_java_lang_String is a global reference to the java.lang.String class
		//MID_String_init is the method ID of the string constructor
		result = (*env)->NewObject(env, Class_java_lang_String, MID_String_init, bytes);
		(*env)->DeleteLocalRef(env, bytes);
		return result;
	} /* else fall through */
	return NULL;
}
jmethodID MID_String_getBytes;
//Translating jstrings to Native Strings
char *JNI_GetStringNativeChars(JNIEnv *env, jstring jstr)
{
	jbyteArray bytes = 0;
	jthrowable exc;
	char *result = 0;
	if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
		return 0; /* out of memory error */
	}
	//MID_String_getBytes is the precomputed method ID of the String.getBytes method
	bytes = (*env)->CallObjectMethod(env, jstr, MID_String_getBytes);
	exc = (*env)->ExceptionOccurred(env);
	if (!exc) {
		jint len = (*env)->GetArrayLength(env, bytes);
		result = (char *)malloc(len + 1);
		if (result == 0) {
			JNU_ThrowByName(env, "java/lang/OutOfMemoryError",
			0);
			(*env)->DeleteLocalRef(env, bytes);
			return 0;
		}
		(*env)->GetByteArrayRegion(env, bytes, 0, len, (jbyte *)result);
		result[len] = 0; /* NULL-terminate */
	} else {
		(*env)->DeleteLocalRef(env, exc);
	}
	(*env)->DeleteLocalRef(env, bytes);
	return result;
}

JavaVM *cached_jvm;
jclass Class_StaticMethodCall;
jmethodID MID_C_callback;

JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
	
	JNIEnv *env;
	jclass cls;
	printf("JNI_OnLoad\n");
	cached_jvm = jvm; /* cache the JavaVM pointer */
	if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
		return JNI_ERR; /* JNI version not supported */
	}
	cls = (*env)->FindClass(env, "StaticMethodCall");
	if (cls == NULL) {
	return JNI_ERR;
	}
	/* Use weak global ref to allow StaticMethodCall class to be unloaded */
	Class_StaticMethodCall = (*env)->NewWeakGlobalRef(env, cls);
	if (Class_StaticMethodCall == NULL) {
	return JNI_ERR;
	}
	/* Compute and cache the method ID */
	MID_C_callback = (*env)->GetStaticMethodID(env, cls, "callback", "()V");
	if (MID_C_callback == NULL) {
	return JNI_ERR;
	}
	return JNI_VERSION_1_2;
}
//通过 cached_jvm 获取当前线程的JNIEnv指针
JNIEnv *JNI_GetEnv()
{
	JNIEnv *env;
	(*cached_jvm)->GetEnv(cached_jvm, (void **)&env, JNI_VERSION_1_2);
	return env;
}

JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *jvm, void *reserved)
{
	JNIEnv *env;
	printf("JNI_OnUnload\n");
	if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
		return;
	}
	(*env)->DeleteWeakGlobalRef(env, Class_StaticMethodCall);
	return;
}